home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 13 - 1997 (partial) / 13.05 May 97 / TidyHeap / CTidyHeap_AC.cp < prev    next >
Encoding:
Text File  |  1997-04-14  |  30.3 KB  |  1,232 lines  |  [TEXT/MPS ]

  1. //----------------------------------------------------------------------------------------
  2. // CTidyHeap_AC.cp
  3. // Copyright © 1984-97 by Apple Computer, Inc. All rights reserved.
  4. //----------------------------------------------------------------------------------------
  5.  
  6. #ifndef __CTidyHeap_AC__
  7. #include "CTidyHeap_AC.h"
  8. #endif
  9.  
  10. #if qTidyHeap
  11.  
  12. // Toolbox
  13. #ifndef __LOWMEM__
  14. #include <LowMem.h>
  15. #endif
  16. #ifndef __SEGLOAD__
  17. #include <SegLoad.h>
  18. #endif
  19. #ifndef __PROCESSES__
  20. #include <Processes.h>
  21. #endif
  22. #ifndef __TEXTUTILS__
  23. #include <TextUtils.h>
  24. #endif
  25.  
  26. // standard libs
  27. #ifndef _STDARG
  28. #include <stdarg.h>
  29. #endif
  30. #ifndef _STRING
  31. #include <string.h>
  32. #endif
  33. #ifndef _STDIO
  34. #include <stdio.h>
  35. #endif
  36.  
  37. // TidyHeap
  38.  
  39.  
  40. #ifndef __CTidyHeapDebugStrLogger_AC__
  41. #include "CTidyHeapDebugStrLogger_AC.h"
  42. #endif
  43. #ifndef __CTidyHeapAction_AC__
  44. #include "CTidyHeapAction_AC.h"
  45. #endif
  46. #ifndef __CTidyHeapActions_AC__
  47. #include "CTidyHeapActions_AC.h"
  48. #endif
  49. #ifndef __CTidyHeapActionsMore_AC__
  50. #include "CTidyHeapActionsMore_AC.h"
  51. #endif
  52. #ifndef __CTidyHeapActionList_AC__
  53. #include "CTidyHeapActionList_AC.h"
  54. #endif
  55. #ifndef __CTidyHeapBlock_AC__
  56. #include "CTidyHeapBlock_AC.h"
  57. #endif
  58. #ifndef __CTidyHeapBlockList_AC__
  59. #include "CTidyHeapBlockList_AC.h"
  60. #endif
  61. #ifndef __CTidyHeapFile_AC__
  62. #include "CTidyHeapFile_AC.h"
  63. #endif
  64. #ifndef __CTidyHeapLogFileLogger_AC__
  65. #include "CTidyHeapLogFileLogger_AC.h"
  66. #endif
  67. #ifndef __CTidyHeap_ACPRIVATE__
  68. #include "CTidyHeapPrivate_AC.h"
  69. #endif
  70. #ifndef __CTidyHeapState_AC__
  71. #include "CTidyHeapState_AC.h"
  72. #endif
  73.  
  74. #ifndef __CActIncrementalNewFailer_AC__
  75. #include "CActIncrementalNewFailer_AC.h"
  76. #endif
  77.  
  78. // TidyHeapSharedLib
  79.  
  80. #ifndef __TIDYHEAPLIB__
  81. #include "TidyHeapSharedLib.h"
  82. #endif
  83.  
  84.  
  85. static const long kHeaderSize = sizeof(BlockHeader) - sizeof(long);
  86. static const long kTrailerSize = sizeof(BlockTrailer);
  87.  
  88. void* operator new(size_t, void* ptr);
  89.     // for some reason I had to declare this. Hmm.
  90.  
  91. GlobalNewProc         CTidyHeap_AC::GlobalNew;
  92. GlobalDeleteProc      CTidyHeap_AC::GlobalDelete;
  93.  
  94. CTidyHeap_AC* CTidyHeap_AC::fgSelf;
  95.  
  96.  
  97. //========================================================================================
  98. // NEW / DELETE Overrides.
  99. //========================================================================================
  100.  
  101. //----------------------------------------------------------------------------------------
  102. // operator new 
  103. //----------------------------------------------------------------------------------------
  104.     
  105. void* operator new(size_t /*size*/, void* ptr, const char* /*file*/ , short /*lineNum*/)
  106. {
  107.     return ptr;
  108.  
  109. //----------------------------------------------------------------------------------------
  110. // operator new 
  111. //----------------------------------------------------------------------------------------
  112.     
  113. void* operator new(size_t /*size*/, void* ptr)
  114. {
  115.     return ptr;
  116. }
  117.  
  118. //----------------------------------------------------------------------------------------
  119. // operator new 
  120. //----------------------------------------------------------------------------------------
  121.     
  122. void* operator new(size_t size)
  123. {
  124.     CTidyHeap_AC* tidyHeap = CTidyHeap_AC::Instance();
  125.     return tidyHeap->CreateBlock(size, NULL, -1) ;
  126. }
  127.  
  128. //----------------------------------------------------------------------------------------
  129. // operator new 
  130. //----------------------------------------------------------------------------------------
  131.     
  132. void* operator new(size_t size, const char* file, short line)
  133. {
  134.     CTidyHeap_AC* tidyHeap = CTidyHeap_AC::Instance();
  135.     return tidyHeap->CreateBlock(size, file, line);
  136. }
  137.  
  138. //----------------------------------------------------------------------------------------
  139. // operator delete 
  140. //----------------------------------------------------------------------------------------
  141.     
  142. void operator delete(void* ptr )
  143. {
  144.     if(ptr)
  145.     {
  146.         CTidyHeap_AC* tidyHeap = CTidyHeap_AC::Instance();
  147.         tidyHeap->RemoveBlock(ptr);
  148.     }
  149. }        
  150.  
  151. //========================================================================================
  152. // class CTidyHeap_AC
  153. //========================================================================================
  154.  
  155. //----------------------------------------------------------------------------------------
  156. // CTidyHeap_AC constructor
  157. //----------------------------------------------------------------------------------------
  158.          
  159. CTidyHeap_AC::CTidyHeap_AC() 
  160.     :    fCount(0),
  161.         fSizeTally(0),
  162.         fDebugTally(0),
  163.         fDeleteCount(0),
  164.         fErr(0),
  165.         fNextNewFails(false),
  166.         fEnabledOnStart(false),
  167.         fLogger(NULL),
  168.         fSettingsFile(NULL),
  169.         fLineNum(0)
  170. {
  171.     fFileName[0] = '\0';
  172.     fLogString[0] = '\0';
  173. }
  174.  
  175. //----------------------------------------------------------------------------------------
  176. // CTidyHeap_AC ITidyHeap
  177. //----------------------------------------------------------------------------------------
  178.     
  179. void CTidyHeap_AC::ITidyHeap()
  180. {
  181.     SetToLogFileLogger();
  182.  
  183.     fSettingsFile = new CTidyHeapFile_AC;
  184.     if(fSettingsFile)
  185.     {
  186.         fSettingsFile->SetTypeAndCreator(kSettingsFileType, kSettingsFileCreator);
  187.         fSettingsFile->AppendExtension(".prf");
  188.         fSettingsFile->ReadObject( *this );
  189.     }
  190.     
  191.     fEnabledOnStart = fPrefs.TestFlag(kEnabled);
  192.     
  193.     InstallPrefActions();
  194.     
  195.     TIDYHEAPSHAREDLIB_SETCALLBACK( Terminate );
  196. }
  197.  
  198. //----------------------------------------------------------------------------------------
  199. // CTidyHeap_AC destructor
  200. //----------------------------------------------------------------------------------------
  201.  
  202. CTidyHeap_AC::~CTidyHeap_AC()
  203. {
  204.     DeleteActions(fDeleteActions);
  205.     DeleteActions(fNewActions);
  206.     DeleteActions(fTerminationActions);    
  207.     
  208.     fSettingsFile->WriteObject( *this );
  209.     delete fSettingsFile;
  210.     
  211.     if(fLogger) delete fLogger;
  212. }
  213.  
  214. //----------------------------------------------------------------------------------------
  215. // CTidyHeap_AC::GetBlockCount
  216. //----------------------------------------------------------------------------------------
  217.  
  218. long CTidyHeap_AC::GetBlockCount() const
  219. {
  220.     if(fgSelf)
  221.         return fgSelf->fBlockList.GetCount();
  222.     else
  223.         return 0;
  224. }    
  225.  
  226. //----------------------------------------------------------------------------------------
  227. // CTidyHeap_AC::FindTrailer
  228. //----------------------------------------------------------------------------------------
  229.  
  230. BlockTrailer* CTidyHeap_AC::FindTrailer(BlockHeader* inBlock)
  231. {
  232.     BlockTrailer* outPtr = (BlockTrailer*) 
  233.         (((char*)inBlock) + sizeof(BlockHeader) + inBlock->fBlockPtr->fSize - sizeof(long));    
  234.         
  235.     if(outPtr->fMarker3 != kMarker3)
  236.     {
  237.         outPtr = NULL;
  238.         fErr = kBadMarker3;
  239.     }
  240.     
  241.     if(fErr)
  242.     {
  243.         LogError();
  244.     }
  245.  
  246.     return outPtr;
  247. }
  248.  
  249. //----------------------------------------------------------------------------------------
  250. // CTidyHeap_AC::CreateBlock
  251. //----------------------------------------------------------------------------------------
  252.  
  253. void* CTidyHeap_AC::CreateBlock(size_t size, const char* file, short line)
  254. {
  255.     void* outPtr = NULL;
  256.     
  257.     if( !IsEnabled() )
  258.         outPtr = GlobalNew(size);
  259.     else
  260.     {
  261.         fCount++; // this is always incremented.
  262.  
  263.         if(fNextNewFails) 
  264.         {
  265.             fNextNewFails = false;
  266.             
  267.             if(!outPtr)
  268.                 HandleNilAllocation();
  269.         }
  270.         else
  271.         {
  272.         
  273.             BlockHeader* headerPtr = (BlockHeader*) GlobalNew(size + kHeaderSize + kTrailerSize);
  274.             if(headerPtr)
  275.             {
  276.                 
  277.                 CTidyHeapBlock_AC*    blockPtr = CreateBlockObject();
  278.                 if(!blockPtr)
  279.                  {
  280.                     GlobalDelete( (void*) headerPtr );
  281.                 }
  282.                 else
  283.                 {
  284.                     // Setup header
  285.                     new(headerPtr) BlockHeader; // call blocks' constructor
  286.                     
  287.                     // Setup trailer
  288.                     new(((char*)headerPtr) + kHeaderSize + size) BlockTrailer;
  289.                 
  290.                     outPtr = &(headerPtr->fData);
  291.                     fDebugTally += kHeaderSize;
  292.                     fSizeTally += size; 
  293.                     
  294.                     blockPtr->fSize = size;
  295.                     blockPtr->fAddress = outPtr;
  296.                     blockPtr->fHeader = headerPtr;
  297.                     blockPtr->fId = fCount;
  298.                     
  299.                     headerPtr->fBlockPtr = blockPtr;
  300.                     
  301.                     if(file)
  302.                     {
  303.                         ::strcpy( blockPtr->fFile, file );
  304.                         blockPtr->fLineNum = line;
  305.                     }
  306.                     else
  307.                     if(::strlen(fFileName))
  308.                     {
  309.                         ::strcpy( blockPtr->fFile, fFileName );
  310.                         blockPtr->fLineNum = fLineNum;
  311.                         fFileName[0] = '\0';
  312.                         fLineNum = 0;
  313.                     }
  314.                     
  315.                     CTidyHeapAction_AC* action = fNewActions.GetHead();
  316.                     
  317.                     while(action)
  318.                     {
  319.                         DoAction( action, headerPtr );
  320.                         action = action->Next();
  321.                     }
  322.                     
  323.                     if(fNextNewFails)
  324.                     {
  325.                         fNextNewFails = false;
  326.                         delete blockPtr;
  327.                         fgSelf->GlobalDelete(headerPtr);    
  328.                         outPtr = NULL;
  329.                         
  330.                         if(!outPtr)
  331.                             HandleNilAllocation();
  332.                     }
  333.                     else
  334.                     if(!blockPtr->IsExempt())
  335.                     {
  336.                         // exempting a block means don't track it
  337.                         fBlockList.Append(blockPtr);
  338.                     }
  339.                     
  340.                 }
  341.             }
  342.         }
  343.     }    
  344.     return outPtr;
  345. }
  346.  
  347. //----------------------------------------------------------------------------------------
  348. // CTidyHeap_AC::FindHeader
  349. //----------------------------------------------------------------------------------------
  350.  
  351.  
  352. BlockHeader* CTidyHeap_AC::FindHeader(char* inPtr)    
  353. {
  354.     fErr = 0;
  355.     
  356.     BlockHeader* outHeader = NULL;
  357.     
  358.     if(GetFeaturePrefs().TestFlag(kPointersLivesInAppHeap))
  359.     {
  360.         if(!PtrInAppHeap(inPtr))
  361.         {
  362.             fErr = kPtrNotInAppHeap;
  363.         }
  364.     }
  365.     
  366.     if(!fErr)
  367.     {    
  368.         // First place to check for the header is immediately on top of the incoming ptr.
  369.         char* walker = inPtr;
  370.     
  371.         walker -= kHeaderSize;
  372.         
  373.         if(CharPtrToLong(walker) == kMarker1)
  374.         {
  375.             outHeader = (BlockHeader*) walker;
  376.         
  377.             if(outHeader->fMarker2 != kMarker2)
  378.             {
  379.                 outHeader = NULL;
  380.                 
  381.                 fErr = kBadMarker2;
  382.             }    
  383.         }
  384.         else
  385.         {
  386.             // If we get here that means the block is either corrupted
  387.             // or the compiler has padded something. So now were going
  388.             // to search backward for one of our markers.
  389.             
  390.             char* startOfValidMem = (inPtr - kHeaderSize);
  391.                 // I'm assuming that the header is there and that we have a block of mem
  392.                 // at least the sizeof the blockheader to search in. I can't guarentee that
  393.                 // mem at location less that startofValidMem is even there.
  394.                       
  395.             for(walker = inPtr; walker >= startOfValidMem; walker--)
  396.             {
  397.                 if(CharPtrToLong(walker) == kMarker2)
  398.                 {
  399.                     // whoo hoo! We found the footMarker.
  400.                 
  401.                     walker -= sizeof( BlockHeader ) - sizeof(long); 
  402.                     
  403.                     if(CharPtrToLong(walker) == kMarker1)
  404.                     {
  405.                         outHeader = (BlockHeader*) walker;
  406.                         
  407.                     }
  408.                     else
  409.                         fErr = kBadMarker1;
  410.                     
  411.                     break;
  412.                 }
  413.                 else
  414.                 if(CharPtrToLong(walker) == kMarker1)
  415.                 {
  416.                     // whoo hoo! We found the headMarker.
  417.                 
  418.                     outHeader = (BlockHeader*) walker;
  419.  
  420.                     if(outHeader->fMarker2 != kMarker2)
  421.                     {
  422.                         outHeader = NULL;
  423.                     }
  424.                     else
  425.                         fErr = kBadMarker2;
  426.                         
  427.                     break;
  428.                 }
  429.                 
  430.             
  431.             }
  432.             
  433.             if(!outHeader && !fErr)
  434.             {
  435.                 fErr = kNoMarkersFound; // yikes!
  436.             }
  437.             
  438.         #if qDebugTidyHeap    
  439.             if(outHeader)
  440.             {
  441.                 long offset = ((char*)outHeader) - inPtr;
  442.                 Logf("### Had to search header for markers. Found the offset at %d", offset);
  443.             }
  444.         #endif    
  445.         
  446.         
  447.         } // else
  448.  
  449.     }    
  450.  
  451.     if(fErr)
  452.         LogError();
  453.     
  454.     return outHeader;
  455. }
  456.  
  457. //----------------------------------------------------------------------------------------
  458. // CTidyHeap_AC::LogError
  459. //----------------------------------------------------------------------------------------
  460.  
  461. void CTidyHeap_AC::LogError()
  462. {
  463.  
  464.     const char* descStr;
  465.     
  466.     switch(fErr)
  467.     {
  468.         // Should probably load these strings from a resource.
  469.         
  470.         case kNoErr:
  471.             descStr = "No Error";
  472.             break;
  473.         
  474.         case kBadMarker1:
  475.             descStr = "Bad Block Header: Marker 1 corrupt";
  476.             break;
  477.         
  478.         case kBadMarker2:
  479.             descStr = "Bad Block Header: Marker 2 corrupt";
  480.             break;
  481.         
  482.         case kBadMarker3:
  483.             descStr = "Bad Block Trailer: Marker 1 corrupt";
  484.             break;
  485.  
  486.         case kNoMarkersFound:
  487.             descStr = "Found no markers at all! (Yikes!)";
  488.             break;
  489.         
  490.         case kPtrCrossRefFailed:
  491.             descStr = "Pointer Cross Reference failed.";
  492.             break;
  493.         
  494.         case kPtrNotInAppHeap:
  495.             descStr = "Block not in Application Heap.";
  496.             break;
  497.         
  498.         default:
  499.             descStr = "Invalid Error value. Run for your life!";
  500.             break;
  501.     
  502.     }
  503.     
  504.     if(GetFeaturePrefs().TestFlag(kWarnings))
  505.     {
  506.         Warnf("TidyHeap Error: %s (%d)", descStr, fErr );
  507.     }
  508.  
  509.     Logf("### TidyHeap Error: %s (%d)", descStr, fErr );
  510. }
  511.  
  512. //----------------------------------------------------------------------------------------
  513. // CTidyHeap_AC::RemoveBlock
  514. //----------------------------------------------------------------------------------------
  515.  
  516. void CTidyHeap_AC::RemoveBlock(void* ptr)
  517. {
  518.     if(!IsEnabled())
  519.         GlobalDelete(ptr);
  520.     else
  521.     {
  522.         fDeleteCount++;
  523.         
  524.         fErr = 0;
  525.         
  526.         // This will log an error if it fails.
  527.         BlockHeader* toDelete = FindHeader((char*) ptr);
  528.             
  529.         if(toDelete && !fErr)
  530.         {
  531.             BlockTrailer* trailer = FindTrailer(toDelete);
  532.         
  533.             CTidyHeapBlock_AC* blockPtr = toDelete->fBlockPtr;
  534.             
  535.             if(trailer && !fErr)
  536.             {
  537.                 CTidyHeapAction_AC* action = fDeleteActions.GetHead();
  538.                 
  539.                 while(action)
  540.                 {
  541.                     DoAction( action, toDelete);
  542.                     action = action->Next();
  543.                 }
  544.                 
  545.                 CTidyHeapAction_AC* deleteAction = toDelete->fBlockPtr->fDeleteAction;
  546.                 
  547.                 if(deleteAction)
  548.                 {
  549.                     DoAction( deleteAction, toDelete);
  550.                     
  551.                     delete deleteAction;            
  552.                     toDelete->fBlockPtr->fDeleteAction = NULL;
  553.                 }        
  554.                 
  555.                 if(blockPtr->fFlags.TestFlag(CTidyHeapBlock_AC::kDeleted))
  556.                 {
  557.                     Logf("### Block Double Delete detected!");
  558.                     Warnf("Block Double Delete detected!");
  559.                     // add more here
  560.                 }
  561.                 else
  562.                 {
  563.                     blockPtr->fFlags.SetFlag(CTidyHeapBlock_AC::kDeleted, true);
  564.                     
  565.                     if(!blockPtr->fFlags.TestFlag(CTidyHeapBlock_AC::kDontDelete))
  566.                     {
  567.                         fBlockList.Remove(blockPtr);
  568.         
  569.                         GlobalDelete((char*)toDelete);
  570.                         
  571.                         delete blockPtr;
  572.                     }
  573.                 }
  574.             }
  575.         }
  576.     }
  577. }
  578.  
  579. //----------------------------------------------------------------------------------------
  580. // CTidyHeap_AC::PushInfo
  581. //----------------------------------------------------------------------------------------
  582.  
  583. void CTidyHeap_AC::PushInfo(const char* file, short lineNum)
  584. {
  585.     fgSelf->fLineNum = lineNum;
  586.     ::strcpy(fgSelf->fFileName, file);
  587. }
  588.  
  589. //----------------------------------------------------------------------------------------
  590. // CTidyHeap_AC::Instance
  591. //----------------------------------------------------------------------------------------
  592.  
  593. CTidyHeap_AC* CTidyHeap_AC::Instance()
  594. {
  595.     static Boolean firstTime = true;
  596.     
  597.     if(firstTime)
  598.     {
  599.         firstTime = false;
  600.  
  601.         CTidyHeap_AC::GlobalNew = (GlobalNewProc) NewPtr;
  602.         CTidyHeap_AC::GlobalDelete = (GlobalDeleteProc) DisposePtr;    
  603.             
  604.         fgSelf = CreateTidyHeap();
  605.         if( !fgSelf )
  606.         {    
  607.             DebugStr("\pUnable to allocate TidyHeap. Something is seriously wrong.");
  608.             ExitToShell();
  609.         }
  610.         fgSelf->ITidyHeap();    
  611.     }
  612.     
  613.     return fgSelf;
  614. }
  615.  
  616. //----------------------------------------------------------------------------------------
  617. // CTidyHeap_AC::Terminate
  618. //----------------------------------------------------------------------------------------
  619.  
  620. void CTidyHeap_AC::Terminate()
  621. {
  622.     if(fgSelf)
  623.     {
  624.         fgSelf->HandleTermination();
  625.             
  626.         delete fgSelf;
  627.         fgSelf = NULL;
  628.  
  629. #if qDebugTidyHeap        
  630.         char str[100];
  631.         
  632.         if(MTidyHeapAllocator_AC::fgAllocationCounter > 0)
  633.         {
  634.             sprintf(str, "Number of TidyHeap's Leaks: %ld;g", MTidyHeapAllocator_AC::fgAllocationCounter);
  635.             c2pstr(str);
  636.             DebugStr((StringPtr)str);
  637.         }
  638. #endif
  639.     }
  640.     
  641. }
  642.  
  643.  
  644. //----------------------------------------------------------------------------------------
  645. // CTidyHeap_AC::Logf
  646. //----------------------------------------------------------------------------------------
  647.  
  648. void CTidyHeap_AC::Logf(const char* format, ...)
  649. {
  650.     if(IsEnabled() && fLogger)
  651.     {
  652.         static va_list args;
  653.         
  654.         va_start(args, format);
  655.         vsprintf(fLogString, format, args);
  656.         va_end(args);
  657.         
  658.         fLogger->Log(fLogString);
  659.     }
  660. }
  661.  
  662. //----------------------------------------------------------------------------------------
  663. // CTidyHeap_AC::Warnf
  664. //----------------------------------------------------------------------------------------
  665.  
  666. void CTidyHeap_AC::Warnf(const char* format, ...)
  667. {
  668.     static va_list args;
  669.     
  670.     if(IsEnabled() && GetWantsWarnings())
  671.     {
  672.         va_start(args, format); // can't globally scope
  673.         ::vsprintf(fLogString, format, args);
  674.         va_end(args); // can't globally scope
  675.     
  676.         ::c2pstr(fLogString);
  677.         
  678.         ::DebugStr((unsigned char*) fLogString);
  679.     }
  680. }
  681.     
  682. //----------------------------------------------------------------------------------------
  683. // CTidyHeap_AC::VerifyAllBlocks
  684. //----------------------------------------------------------------------------------------
  685.  
  686. void CTidyHeap_AC::VerifyAllBlocks(Boolean logBlockData)
  687. {
  688.     if(IsEnabled())
  689.     {
  690.         long size = 0;
  691.         if(!fBlockList.IsEmpty())
  692.         {
  693.             CTidyHeapBlock_AC* walker = fBlockList.GetHead();
  694.             
  695.             while(walker)
  696.             {
  697.                 
  698.                 VerifyBlock( walker->fAddress, logBlockData );
  699.                 size += walker->fSize;
  700.                 
  701.                 walker = walker->Next();
  702.             }
  703.             
  704.             Logf("### Sum of outstanding block sizes = %ld bytes.", size );
  705.         }
  706.     }
  707. }
  708.  
  709. //----------------------------------------------------------------------------------------
  710. // CTidyHeap_AC::VerifyBlock
  711. //----------------------------------------------------------------------------------------
  712.  
  713. CTidyHeapError_AC CTidyHeap_AC::VerifyBlock(void* inBlock, Boolean logBlockData)
  714. {
  715.     if(IsEnabled())
  716.     {
  717.         CTidyHeapBlock_AC* block = 0;
  718.         BlockHeader* header = FindHeader((char*) inBlock);
  719.         BlockTrailer* trailer = NULL;
  720.             
  721.         if(header && !fErr)
  722.             trailer = FindTrailer(header);
  723.  
  724.         if(!fErr)
  725.         {
  726.             block = header->fBlockPtr;
  727.             
  728.             if(    (block->fAddress != inBlock) || (block->fHeader != header))
  729.             {
  730.                 fErr = kPtrCrossRefFailed;
  731.             }
  732.             else
  733.             if( logBlockData )
  734.                 block->LogBlockData();
  735.         }
  736.  
  737.         if(fErr)
  738.         {
  739.             // already logged the error in FindHeader or FindTrailer
  740.             if(block) block->LogBlockData();    
  741.         }
  742.     }
  743.         
  744.     return fErr;
  745. }
  746.  
  747. //----------------------------------------------------------------------------------------
  748. // CTidyHeap_AC::SetDebugStrHook
  749. //----------------------------------------------------------------------------------------
  750.  
  751. void CTidyHeap_AC::SetToDebugStrLogger( Boolean doHalt)
  752. {
  753.     AquireLogger( new CTidyHeapDebugStrLogger_AC(doHalt) );
  754. }
  755.  
  756. //----------------------------------------------------------------------------------------
  757. // CTidyHeap_AC::SetLogFileHook
  758. //----------------------------------------------------------------------------------------
  759.  
  760. void CTidyHeap_AC::SetToLogFileLogger()
  761. {
  762.     AquireLogger( new CTidyHeapLogFileLogger_AC );
  763. }
  764.  
  765. //----------------------------------------------------------------------------------------
  766. // CTidyHeap_AC::VerifyState
  767. //----------------------------------------------------------------------------------------
  768.  
  769. long CTidyHeap_AC::VerifyState(CTidyHeapState_AC &inShot)
  770. {
  771.     long count = 0;
  772.     
  773.     if(IsEnabled())
  774.     {
  775.         BlockHeader* marker = FindHeader( (char*) inShot.fMarker );
  776.         
  777.         if( marker->fBlockPtr != fBlockList.GetTail())
  778.         {
  779.             Logf("### Warning: outstanding blocks remaining after state saved.");
  780.             
  781.             CTidyHeapBlock_AC* walker = marker->fBlockPtr->Next();
  782.             
  783.             while(walker)
  784.             {
  785.                 VerifyBlock( walker->fAddress );
  786.                 count++;
  787.                 walker = walker->Next();
  788.             }
  789.             
  790.             Logf("### Num new blocks since state saved: %ld", count);
  791.         }
  792.         else
  793.         {
  794.             Logf("### State detected no leaks.");
  795.         }
  796.     }
  797.     
  798.     return count;
  799. }
  800.  
  801. //----------------------------------------------------------------------------------------
  802. // CTidyHeap_AC::DeleteActions
  803. //----------------------------------------------------------------------------------------
  804.  
  805. void CTidyHeap_AC::DeleteActions( CTidyHeapActionList_AC &inList )
  806. {
  807.     // Note:this should be a list method.
  808.     
  809.     CTidyHeapAction_AC* walker = inList.GetHead();
  810.     CTidyHeapAction_AC* deleter = NULL;
  811.     
  812.     while(walker)
  813.     {
  814.         deleter = walker;
  815.         walker = walker->Next();
  816.     
  817.         if(deleter) 
  818.         {
  819.             inList.Remove(deleter);
  820.             delete deleter;    
  821.         }
  822.     }
  823.  
  824. }
  825.  
  826. //----------------------------------------------------------------------------------------
  827. // CTidyHeap_AC::DoAction
  828. //----------------------------------------------------------------------------------------
  829.  
  830. void CTidyHeap_AC::DoAction( CTidyHeapAction_AC* action, BlockHeader* header)
  831. {
  832.     if(header)
  833.     {
  834.         action->DoAction(header->fBlockPtr);
  835.     }
  836.     else
  837.     {
  838.         action->DoAction(NULL);
  839.     }
  840. }
  841.  
  842.  
  843.  
  844. //----------------------------------------------------------------------------------------
  845. // CTidyHeap_AC::GetBlock
  846. //----------------------------------------------------------------------------------------
  847.  
  848. CTidyHeapBlock_AC* CTidyHeap_AC::GetBlock(void* inPtr)
  849. {
  850.     
  851.     CTidyHeapBlock_AC* outBlock = NULL;
  852.     
  853.     if(IsEnabled())
  854.     {
  855.         fErr = 0;
  856.         
  857.         
  858.         BlockHeader* header = FindHeader((char*) inPtr);
  859.         if(header)
  860.         {
  861.             outBlock = header->fBlockPtr;
  862.         }
  863.     }    
  864.     return outBlock;
  865. }
  866.  
  867. //----------------------------------------------------------------------------------------
  868. // CTidyHeap_AC::GetMarker
  869. //----------------------------------------------------------------------------------------
  870.  
  871. CTidyHeapMarker_AC CTidyHeap_AC::GetMarker( void* inPtr, short markerNum )
  872. {
  873.     fErr = 0;
  874.     CTidyHeapMarker_AC outMarker = 0xF0F0F0F0;
  875.     
  876.     if(IsEnabled())
  877.     {
  878.         BlockHeader* header = FindHeader((char*)inPtr);
  879.         if(header)
  880.         {
  881.             switch( markerNum )
  882.             {
  883.                 case 1:
  884.                     outMarker = header->fMarker1;
  885.                     break;
  886.                 
  887.                 case 2:
  888.                     outMarker = header->fMarker2;
  889.                     break;
  890.                 
  891.                 case 3:
  892.                     BlockTrailer* trailer = FindTrailer(header);
  893.                     if(!fErr)
  894.                     {
  895.                         outMarker = trailer->fMarker3;
  896.                     }    
  897.                 
  898.                     break;
  899.             
  900.             }    
  901.         }
  902.     }
  903.     return outMarker;
  904. }
  905.  
  906. //----------------------------------------------------------------------------------------
  907. // CTidyHeap_AC::CreateBlockObject
  908. //----------------------------------------------------------------------------------------
  909.  
  910. CTidyHeapBlock_AC* CTidyHeap_AC::CreateBlockObject()
  911. {
  912.     return new CTidyHeapBlock_AC;
  913. }
  914.  
  915. //----------------------------------------------------------------------------------------
  916. // CTidyHeap_AC::MakeNextNewFail
  917. //----------------------------------------------------------------------------------------
  918.  
  919. void CTidyHeap_AC::MakeNextNewFail()
  920. {
  921.     fNextNewFails = true;
  922. }
  923.  
  924. //----------------------------------------------------------------------------------------
  925. // CTidyHeap_AC::AquireNewAction
  926. //----------------------------------------------------------------------------------------
  927.  
  928. void CTidyHeap_AC::AquireNewAction( CTidyHeapAction_AC* inAction )
  929. {
  930.     fNewActions.Append(inAction);
  931. }
  932.  
  933. //----------------------------------------------------------------------------------------
  934. // CTidyHeap_AC::RemoveNewAction
  935. //----------------------------------------------------------------------------------------
  936.  
  937. void CTidyHeap_AC::RemoveNewAction( CTidyHeapAction_AC* inAction)
  938. {
  939.     fNewActions.Remove(inAction);
  940. }
  941.  
  942.  
  943. //----------------------------------------------------------------------------------------
  944. // CTidyHeap_AC::AquireDeleteAction
  945. //----------------------------------------------------------------------------------------
  946.  
  947. void CTidyHeap_AC::AquireDeleteAction( CTidyHeapAction_AC* inAction)
  948. {
  949.     fDeleteActions.Append(inAction);
  950. }
  951.  
  952. //----------------------------------------------------------------------------------------
  953. // CTidyHeap_AC::RemoveDeleteAction
  954. //----------------------------------------------------------------------------------------
  955.  
  956. void CTidyHeap_AC::RemoveDeleteAction( CTidyHeapAction_AC* inAction )
  957. {
  958.     fDeleteActions.Remove(inAction);
  959. }
  960.  
  961. //----------------------------------------------------------------------------------------
  962. // CTidyHeap_AC::AquireTerminationAction
  963. //----------------------------------------------------------------------------------------
  964.  
  965. void CTidyHeap_AC::AquireTerminationAction( CTidyHeapAction_AC* inAction )
  966. {
  967.     fTerminationActions.Append(inAction);
  968. }
  969.  
  970. //----------------------------------------------------------------------------------------
  971. // CTidyHeap_AC::RemoveTerminationAction
  972. //----------------------------------------------------------------------------------------
  973.  
  974. void CTidyHeap_AC::RemoveTerminationAction( CTidyHeapAction_AC* inAction)
  975. {
  976.     fTerminationActions.Remove(inAction);
  977. }
  978.  
  979. //----------------------------------------------------------------------------------------
  980. // CTidyHeap_AC::GetTerminationActionList
  981. //----------------------------------------------------------------------------------------
  982.  
  983. CTidyHeapActionList_AC& CTidyHeap_AC::GetTerminationActionList()
  984. {
  985.     return fTerminationActions;
  986. }
  987.  
  988. //----------------------------------------------------------------------------------------
  989. // CTidyHeap_AC::GetNewActionsList
  990. //----------------------------------------------------------------------------------------
  991.  
  992. CTidyHeapActionList_AC& CTidyHeap_AC::GetNewActionsList()
  993. {
  994.     return fNewActions;
  995. }
  996.     
  997. //----------------------------------------------------------------------------------------
  998. // CTidyHeap_AC::GetDeleteActionList
  999. //----------------------------------------------------------------------------------------
  1000.  
  1001. CTidyHeapActionList_AC& CTidyHeap_AC::GetDeleteActionList()
  1002. {
  1003.     return fDeleteActions;
  1004. }
  1005.  
  1006. //----------------------------------------------------------------------------------------
  1007. // CTidyHeap_AC::IsEnabled
  1008. //----------------------------------------------------------------------------------------
  1009.  
  1010. Boolean CTidyHeap_AC::IsEnabled() const
  1011. {
  1012.     return fEnabledOnStart;
  1013. }
  1014.  
  1015. //----------------------------------------------------------------------------------------
  1016. // CTidyHeap_AC::SetIsEnabled
  1017. //----------------------------------------------------------------------------------------
  1018.  
  1019. void CTidyHeap_AC::SetIsEnabled(Boolean isEnabled)
  1020. {
  1021.     CTidyHeapSettings_AC::SetIsEnabled(isEnabled);
  1022. }
  1023.  
  1024. //----------------------------------------------------------------------------------------
  1025. // CTidyHeap_AC::AquireLogger
  1026. //----------------------------------------------------------------------------------------
  1027.  
  1028.  CTidyHeapLogger_AC * CTidyHeap_AC::AquireLogger( CTidyHeapLogger_AC *inLogger, Boolean deletePrevious)
  1029. {
  1030.     CTidyHeapLogger_AC *outLogger = NULL;
  1031.  
  1032.     if(fLogger)
  1033.     {
  1034.         if(deletePrevious)
  1035.             delete fLogger;
  1036.         else
  1037.             outLogger = fLogger;
  1038.     }
  1039.         
  1040.     fLogger = inLogger;
  1041.  
  1042.     return outLogger;
  1043. }
  1044.  
  1045. //----------------------------------------------------------------------------------------
  1046. // CTidyHeap_AC::RemoveAllActions
  1047. //----------------------------------------------------------------------------------------
  1048.  
  1049. void CTidyHeap_AC::RemoveAllActions()
  1050. {
  1051.     DeleteActions( fNewActions );
  1052.     DeleteActions( fDeleteActions );
  1053. }
  1054.  
  1055. //----------------------------------------------------------------------------------------
  1056. // CTidyHeap_AC::InstallPrefActions
  1057. //----------------------------------------------------------------------------------------
  1058.  
  1059. void CTidyHeap_AC::InstallPrefActions()
  1060. {
  1061.     for(short i = 0; i < kNumActions; i++)
  1062.     {
  1063.         switch(i)
  1064.         {
  1065.             case kDoubleDeleteWatcher:
  1066.                 if( fActions.TestFlag(i) )
  1067.                     AquireDeleteAction( new CActionDoubleDeleteWatcher_AC );
  1068.                 break;
  1069.             
  1070.             case kMakeNewFail:
  1071.                 if( fActions.TestFlag(i) )
  1072.                     AquireNewAction( new CActionMakeNewFail_AC(fNewFailCount) );
  1073.                 break;
  1074.             
  1075.             case kIncrementalFailer:
  1076.                 if( fActions.TestFlag(i) )
  1077.                     AquireNewAction(  new CActionIncrementalNewFailer_AC ); 
  1078.                 break;
  1079.             
  1080.             case kNewVerifyAction:
  1081.                 if( fActions.TestFlag(i) )
  1082.                     AquireNewAction( new CActionVerifyBlock_AC ); 
  1083.                 break;
  1084.             
  1085.             case kDeleteVerifyAction:
  1086.                 if( fActions.TestFlag(i) )
  1087.                     AquireDeleteAction( new CActionVerifyBlock_AC ); 
  1088.                 break;
  1089.             
  1090.             case kNewVerifyAllAction:
  1091.                 if( fActions.TestFlag(i) )
  1092.                     AquireNewAction(new CActionVerifyAll_AC ); 
  1093.                 break;
  1094.  
  1095.             case kDeleteVerifyAllAction:
  1096.                 if( fActions.TestFlag(i) )
  1097.                     AquireDeleteAction(new CActionVerifyAll_AC ); 
  1098.                 break;
  1099.                 
  1100.             case kExemptUnknownBlocks:
  1101.                 if( fActions.TestFlag(i) )
  1102.                     AquireNewAction(new CActionExcemptUnknownBlocks_AC ); 
  1103.                 break;
  1104.             
  1105.             case kGarbageIn:
  1106.                 if( fActions.TestFlag(i) )
  1107.                     AquireNewAction(new CActionGarbageIn_AC ); 
  1108.                 break;
  1109.             
  1110.             case kGarbageOut:
  1111.                 if( fActions.TestFlag(i) )
  1112.                     AquireDeleteAction(new CActionGarbageOut_AC ); 
  1113.                 break;
  1114.                 
  1115.             case kNewBreakOnUnknownBlock:
  1116.                 if( fActions.TestFlag(i) )
  1117.                     AquireNewAction(new CActionBreakOnUnknownBlock_AC ); 
  1118.                 break;
  1119.             
  1120.             case kDeleteBreakOnUnknownBlock:
  1121.                 if( fActions.TestFlag(i) )
  1122.                     AquireDeleteAction(new CActionBreakOnUnknownBlock_AC ); 
  1123.                 break;
  1124.         }
  1125.     }
  1126. }
  1127.  
  1128. //----------------------------------------------------------------------------------------
  1129. // CTidyHeap_AC::GetSessionFileLoc
  1130. //----------------------------------------------------------------------------------------
  1131.  
  1132. void CTidyHeap_AC::GetSessionFileLoc(short& vol, long &dirId)
  1133. {
  1134.     vol = 0;
  1135.     dirId = 0;
  1136. }
  1137.  
  1138. //----------------------------------------------------------------------------------------
  1139. // CTidyHeap_AC::HandleNilAllocation
  1140. //----------------------------------------------------------------------------------------
  1141.  
  1142. void CTidyHeap_AC::HandleNilAllocation()
  1143. {
  1144.     // override this if you want to throw an exception or something.
  1145.     
  1146. }
  1147.  
  1148. //----------------------------------------------------------------------------------------
  1149. // CTidyHeap_AC::GetErr
  1150. //----------------------------------------------------------------------------------------
  1151.  
  1152. CTidyHeapError_AC CTidyHeap_AC::GetErr()
  1153. {
  1154.     return fErr;
  1155. }
  1156.  
  1157. //----------------------------------------------------------------------------------------
  1158. // CTidyHeap_AC::GetBlockList
  1159. //----------------------------------------------------------------------------------------
  1160.  
  1161. CTidyHeapBlockList_AC& CTidyHeap_AC::GetBlockList()
  1162. {
  1163.     return fBlockList;
  1164. }
  1165.  
  1166. //----------------------------------------------------------------------------------------
  1167. // CTidyHeap_AC::PtrInAppHeap
  1168. //----------------------------------------------------------------------------------------
  1169.  
  1170. Boolean CTidyHeap_AC::PtrInAppHeap(void* inPtr)
  1171. {
  1172.     THz appZone = ::LMGetApplZone();
  1173.     return inPtr >= &(appZone->heapData) && inPtr < appZone->bkLim;
  1174. }
  1175.  
  1176. //----------------------------------------------------------------------------------------
  1177. // CTidyHeap_AC::HandleTermination
  1178. //----------------------------------------------------------------------------------------
  1179.  
  1180. void CTidyHeap_AC::HandleTermination()
  1181. {
  1182.     if(IsEnabled())
  1183.     {
  1184.         Logf("### TidyHeap Termination Messages:");
  1185.         
  1186.         Logf("### %d Outstanding blocks, %ld total blocks, Ave Size %f",
  1187.             GetBlockCount(), 
  1188.             GetBlockCountTally(),
  1189.             GetAveSize() );
  1190.         
  1191.         Logf("### New called %d times, Delete called %d times",
  1192.              GetBlockCountTally(),
  1193.              fDeleteCount);
  1194.     
  1195.         if(    GetFeaturePrefs().TestFlag( CTidyHeapSettings_AC::kUndeletedBlockWarning ) &&
  1196.             GetBlockCount())
  1197.             Warnf("TidyHeap Warning: you have %ld undeleted blocks.;g", GetBlockCount() );
  1198.         
  1199.         if(    GetFeaturePrefs().TestFlag( CTidyHeapSettings_AC::kLogUndeletedBlocks ) )
  1200.         {
  1201.             VerifyAllBlocks(true); // true means log the block data
  1202.         }
  1203.         
  1204.         CTidyHeapAction_AC* actionWalker = fTerminationActions.GetHead();
  1205.         
  1206.         while(actionWalker)
  1207.         {
  1208.             DoAction(actionWalker, NULL);
  1209.             actionWalker = actionWalker->Next();
  1210.         }
  1211.  
  1212.     }
  1213.  
  1214. }
  1215.  
  1216. //----------------------------------------------------------------------------------------
  1217. // CTidyHeap_AC::ExemptBlockFromLeakCheck
  1218. //----------------------------------------------------------------------------------------
  1219.  
  1220. void CTidyHeap_AC::ExemptBlockFromLeakCheck(void* inBlock)
  1221. {
  1222.     CTidyHeapBlock_AC* theBlock = Instance()->GetBlock(inBlock);
  1223.     if(theBlock)
  1224.     {
  1225.         theBlock->SetExempt(true);
  1226.     }
  1227. }
  1228.  
  1229.  
  1230.  
  1231. #endif